#pragma once
#include "platform.h"
#include "hash_tables.h"
#include "libgrf.h" // grf_callback
#include <vector>
class GrfFile;
class GrfNode;
class GrfTreeNode;


class GrfFile
{
private:
	uint32_t m_table_offset;
	uint32_t m_table_size;
	uint32_t m_version;
	int m_fd;
	int m_compression_level;
	int m_wasted_space;
	bool m_need_save;
	bool m_write_mode;
	GrfNode* m_first_node; // linked list
	HashTable<GrfNode>* m_fast_table; // name lookup table for 'first_node'
	GrfTreeNode* m_root;
	grf_callback* m_callback;
	void* m_callback_etc;

public:
	GrfFile::GrfFile(int fd, bool writemode);
	GrfFile::~GrfFile(void);

	GrfTreeNode* GrfFile::grf_tree_get_root(void);
	GrfNode* GrfFile::grf_get_file(const char* filename);
	GrfNode* GrfFile::grf_get_file_first(void);
	uint32_t GrfFile::grf_get_file_list(GrfNode** arr, size_t num);
	uint32_t GrfFile::filecount(void) const;
	uint32_t GrfFile::wasted_space(void) const;
	void GrfFile::grf_set_compression_level(int level);
	void GrfFile::grf_set_callback(grf_callback* callback, void* etc);

	GrfNode* GrfFile::grf_file_add(const char* filename, const void* ptr, size_t size);
	GrfFile* GrfFile::grf_load_from_new(void);
	bool GrfFile::grf_file_rename(GrfNode* node, const char* newname);
	bool GrfFile::grf_file_delete(GrfNode* node);
	uint32_t GrfFile::grf_file_get_contents(GrfNode* node, void* outbuf);
	bool GrfFile::grf_save(void);
	bool GrfFile::grf_merge(GrfFile* src, uint8_t repack_type);
	bool GrfFile::grf_repack(uint8_t repack_type);
	void GrfFile::grf_create_tree(void);
	static GrfFile* __cdecl GrfFile::grf_new(const char* filename, bool writemode);
	static GrfFile* __cdecl GrfFile::grf_new_by_fd(int fd, bool writemode);

private:
	bool GrfFile::prv_grf_load(void);
	bool GrfFile::prv_grf_write_header(void);
	bool GrfFile::prv_grf_write_table(void);
	GrfNode* GrfFile::prv_grf_find_free_space(size_t size);
	bool GrfFile::prv_grf_quicksort(void);
	void GrfFile::prv_grf_recount_wasted_space(void);
	void GrfFile::prv_linkedlist_attach(GrfNode* node, GrfNode* anchor);
	GrfNode* GrfFile::prv_grf_file_add(const char* filename, uint8_t flags, uint32_t real_size, uint32_t zlen, uint32_t zlen_aligned, const uint8_t* zdata);
};
